package bandidong.dao.impl;

import bandidong.dao.OrdersDAO;
import bandidong.model.Customer;
import bandidong.model.Orders;
import bandidong.transfermodel.SearchOrdersTransferModel;
import bandidong.utils.Constant;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

public class OrdersDAOImpl implements OrdersDAO {
    
    private EntityManager em;
    
    public OrdersDAOImpl(EntityManager em) {
        this.em = em;
    }
    
    @Override
    public List<Orders> getAllOrders() {
        try {
            String jpaql = "SELECT o FROM Orders o";
            Query query = em.createQuery(jpaql);
            List<Orders> orders = (List<Orders>) query.getResultList();
            return orders;
        }
        catch (Exception ex) {
            return null;
        }
    }

    @Override
    public Orders getOrderById(int orderId) {
        try {
            String jpaql = "SELECT o FROM Orders o WHERE o.orderId = :orderId";
            Query query = em.createQuery(jpaql);
            query.setParameter("orderId", orderId);
            List<Orders> orders = (List<Orders>) query.getResultList();
            if (orders != null && !orders.isEmpty()) {
                return orders.get(0);
            }
            return null;
        }
        catch (Exception ex) {
            return null;
        }
    }

    @Override
    public Orders addOrder(Orders order) {
        try {
            em.persist(order);
            em.flush();
            return order;
        }
        catch (Exception ex) {
            return null;
        }
    }

    @Override
    public String updateOrder(Orders order) {
        try {
            Orders o = em.find(Orders.class, order.getOrderId());
            o.setOrderDate(order.getOrderDate());
            o.setIsDeliver(order.isIsDeliver());
            o.setCustomer(order.getCustomer());
            o.setOrderDetailsSet(order.getOrderDetailsSet());
            em.merge(o);
            return Constant.SUCCESS;
        }
        catch (Exception ex) {
            return Constant.ERROR;
        }
    }

    @Override
    public String deleteOrder(Orders order) {
        try {
            Orders o = em.find(Orders.class, order.getOrderId());
            em.remove(o);
            return Constant.SUCCESS;
        }
        catch (Exception ex) {
            return Constant.ERROR;
        }
    }

    @Override
    public List<Orders> getOrdersCriteria(SearchOrdersTransferModel model, int page, int pageSize) {
        Query query = getOrdersWithoutPagging(model);
        if (page <= 0 || pageSize <= 0) {
            return null;
        }
        return query == null ? null : query
                .setFirstResult((page - 1) * pageSize)
                .setMaxResults(pageSize).getResultList();
    }
    
    private Query getOrdersWithoutPagging(SearchOrdersTransferModel model) {
        try {
            CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
            CriteriaQuery<Orders> criteriaQuery = criteriaBuilder.createQuery(Orders.class);
            Root<Orders> root = criteriaQuery.from(Orders.class);
            
            List<Predicate> predicates = new ArrayList<Predicate>();
            // Filter orderId
            if (model.getOrderId() != null && !"".equals(model.getOrderId())) {
                Expression<Integer> orderId = root.get("orderId");
                predicates.add(criteriaBuilder.equal(orderId, Integer.parseInt(model.getOrderId())));
            }
            // Filter deliver
            Expression<Boolean> isDeliver = root.get("isDeliver");
            predicates.add(criteriaBuilder.equal(isDeliver, model.isIsDeliver()));
            // Filter order date
            if (model.getFromOrderDate() != null) {
                ParameterExpression<Date> fromOrderDateParam = criteriaBuilder.parameter(Date.class, "fromOrderDateParam");
                Expression<Date> orderDate = root.<Date>get("orderDate");
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(orderDate, fromOrderDateParam));
            }
            if (model.getToOrderDate() != null) {
                ParameterExpression<Date> toOrderDateParam = criteriaBuilder.parameter(Date.class, "toOrderDateParam");
                Expression<Date> orderDate = root.<Date>get("orderDate");
                predicates.add(criteriaBuilder.lessThanOrEqualTo(orderDate, toOrderDateParam));
            }
            // Customer information
            String customerName = model.getCustomerName();
            String customerAddress = model.getCustomerAddress();
            String customerPhoneNumber = model.getCustomerPhoneNumber();
            String customerEmail = model.getCustomerEmail();
            
            if ((customerName != null && !"".equals(customerName)) || (customerAddress != null && !"".equals(customerAddress)) ||
                    (customerPhoneNumber != null && !"".equals(customerPhoneNumber)) || (customerEmail != null && !"".equals(customerEmail))) {
                Join<Orders, Customer> join = root.join("customer");
                // Filter customer name
                if (customerName != null && !"".equals(customerName)) {
                    predicates.add(criteriaBuilder.equal(join.get("customerName"), customerName));
                }
                if (customerAddress != null && !"".equals(customerAddress)) {
                    predicates.add(criteriaBuilder.equal(join.get("customerAddress"), customerAddress));
                }
                if (customerPhoneNumber != null && !"".equals(customerPhoneNumber)) {
                    predicates.add(criteriaBuilder.equal(join.get("customerPhoneNumber"), customerPhoneNumber));
                }
                if (customerEmail != null && !"".equals(customerEmail)) {
                    predicates.add(criteriaBuilder.equal(join.get("customerEmail"), customerEmail));
                }
            }
            
            criteriaQuery.select(root).where(predicates.toArray(new Predicate[predicates.size()]));
            TypedQuery<Orders> query = em.createQuery(criteriaQuery);
            if (model.getFromOrderDate() != null) {
                query.setParameter("fromOrderDateParam", model.getFromOrderDate());
            }
            if (model.getToOrderDate() != null) {
                query.setParameter("toOrderDateParam", model.getToOrderDate());
            }
            return query;
        }
        catch (Exception ex) {
            return null;
        }
    }
    
    @Override
    public List<Orders> getOrdersCriteria(SearchOrdersTransferModel model) {
        Query query = getOrdersWithoutPagging(model);
        return query == null ? null : query.getResultList();
    }
}
